#ifndef _EBN_MODEL_H_
#define _EBN_MODEL_H_

#define GETMODEL()       CEbnModel::getModel()
#define GETPARAM()       GETMODEL()->getNetParamManager()
#define GETMSGRECEIVER() GETMODEL()->getActionMsgReceiver()

#define UNIT_PER_SEC     1000
#define DEFAULT_INTERVAL 5 * UNIT_PER_SEC     // 5 sec

#include "EbnCompetenceModule.h"
#include "EbnReception.h"
#include "EbnGoal.h"
#include "EbnLink.h"
#include "EbnReceptor.h"
#include "EbnCMEnergyHistFromGoal.h"
#include "EbnNetParamManager.h"

#include "EbnActionMsgReceiver.h"

#include <QObject>

class CEbnModel : public QObject
{
    Q_OBJECT

public:
    explicit CEbnModel(QObject *parent = 0);
    ~CEbnModel(void);

    void addCompetenceModule(CEbnCompetenceModule * pCompetenceModule);
    void addGoal(CEbnGoal * pGoal);    
    void addReceptor(CEbnReceptor * pReceptor);

    void removeReceptor(CEbnReceptor * pReceptor);
    void removeCompetenceModule(CEbnCompetenceModule * pModule);
    void removeGoal(CEbnGoal * pGoal);


    bool hasCompetenceModule(CEbnCompetenceModule * pCompetenceModule);
    bool hasGoal(CEbnGoal * pGoal);
    bool hasReceptor(CEbnReceptor * pReceptor);

    CEbnReceptor * findReceptor(CEbnWorldState * worldState);
    CEbnGoal * findGoal(CEbnWorldState * worldState);
    CEbnCompetenceModule * findCompetenceModule(CEbnAction * action);

    bool isModelStarted(void);
    bool isModelRunning(void);

    int getStepCount();
    void increaseStepCount();
    void resetStepCount();

    void setStepInterval(int sec);
    int getStepInterval(void);

    bool start(void);
    void stop(void);

    void update(void);
    void run(void);
    void pause(void);

    void reset(void);
    void clear(void);

    bool selectActionToDo(void);

    static CEbnModel * getModel();
    CEbnNetParamManager * getNetParamManager(void);
    CEbnActionMsgReceiver * getActionMsgReceiver(void);

    void createLink(CEbnReceptor * from, CEbnCompetenceModule * to);
    void createLink(CEbnGoal * from, CEbnCompetenceModule * to);
    void createLink(CEbnCompetenceModule * from, CEbnCompetenceModule * to);

    static CEbnModel * mpSingleInstance;

    QString getCompetenceModuleInfo(int index);
    QString getGoalInfo(int index);
    QString getReceptorInfo(int index);
    QString getModelInfo();

    int getGoalCount();
    int getCompetenceModuleCount();
    int getReceptorCount();
    int getLinkCount();

protected:
    void timerEvent( QTimerEvent *event );

    CEbnGoal * getGoal(int index);
    CEbnCompetenceModule * getCompetenceModule(int index);
    CEbnLink * getLink(int index);
    CEbnReceptor * getReceptor(int index);

    void wait(int sec);

    void updateActivation(void);

    void initializeLinks(void);
    void uninitializeLinks(void);

    void initializeHistByGoal(void);
    void uninitializeHistByGoal(void);

    bool hasLink(CEbnLink * pLink);
    void addLink(CEbnLink * pLink);

    bool saveToHist(CEbnGoal * goal, CEbnCompetenceModule * cm, float activation);
    float getActivationHist(CEbnGoal * goal, CEbnCompetenceModule * cm, int time);

    CEbnPredecessorLink * createPredecessorLink(CEbnCompetenceModule * from, CEbnCompetenceModule * to, CEbnEffect * pFromEffect, CEbnCondition * pToCondition);
    CEbnSuccessorLink * createSuccessorLink(CEbnCompetenceModule * from, CEbnCompetenceModule * to, CEbnCondition * pFromCondition, CEbnEffect * pToEffect);
    CEbnConflictorLink * createConflictorLink(CEbnCompetenceModule * from, CEbnCompetenceModule * to, CEbnCondition * pFromCondition, CEbnEffect * pToEffect);
    CEbnGoalLink * createGoalLink(CEbnGoal * from, CEbnCompetenceModule * to, CEbnCondition * pFromCondition, CEbnEffect * pToEffect);
    CEbnReceptorLink* createReceptorLink(CEbnReceptor * from, CEbnCompetenceModule * to, CEbnReception * pFromReceiption, CEbnCondition * pToCondition);

signals:
    void notifyUpdated();

private:

    vector<CEbnCompetenceModule *> mCompetenceModules;
    vector<CEbnGoal *> mGoals;
    vector<CEbnLink *> mLinks;
    vector<CEbnReceptor *> mReceptors;

    vector<CEbnCMEnergyHistFromGoal *> mHistsByGoal;

    bool mModelStarted;

    int mTime;
    int mStepInterval;
    int mUpdateTimerId;

    bool mRunning;

    CEbnNetParamManager * mpNetParamManager;
    CEbnActionMsgReceiver * mpActionMsgReceiver;
};

#endif
